package io.renren.modules.media.ffmpeg;

import lombok.extern.log4j.Log4j2;
import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.FFmpegFrameRecorder;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.bytedeco.javacv.OpenCVFrameConverter;
import org.bytedeco.opencv.global.opencv_core;
import org.bytedeco.opencv.opencv_core.IplImage;

import com.google.common.collect.Lists;

import io.renren.common.utils.DateUtils;
import io.renren.common.utils.FileUtil;
import io.renren.modules.media.enums.TimeoutOption;
import io.renren.modules.media.model.ImageInfo;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List;

import javax.imageio.ImageIO;

//import static org.bytedeco.ffmpeg.global.avcodec.*;
//import static org.bytedeco.ffmpeg.global.avutil.*;

/**
 * 点播-视频介质
 * 均匀按秒切分
 * */
@Log4j2
public class MediaProcessing {
	public static final String yyyyMMdd = "yyyyMMdd";
    public static final String timeout = "5000000";
    public static final String Suffix = ".";
    public static final String FitterFormat = "mp4";

    /**
     * 截取从第start秒到第end秒的视频
     * @param inputFilePath 输入文件地址
     * @param start 碎片开始时间
     * @param end 碎片结束时间
     * @param outputFile 输出文件
     *
     * **/
    public static String cutVideo(String inputFilePath,double start, double end){
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;

		StringBuffer output = new StringBuffer();
		output.append("./media/").append(DateUtils.dateToStr(new Date(), yyyyMMdd)).append("/cut").append("/");
		String outputPath = output.toString();
        FileUtil.judeDirExists(new File(outputPath));
        
        String outputFile = outputPath +System.currentTimeMillis()+ Suffix + FitterFormat;

        try {
            grabber = new FFmpegFrameGrabber(inputFilePath);
            grabber.setOption(TimeoutOption.RW_TIMEOUT.getKey(), timeout);
            grabber.start();
            if (grabber.getLengthInVideoFrames() == 0 || grabber.getVideoFrameRate() == 0) {
                log.error("file:{} 信息不全",inputFilePath);
                return null;
            }
            //微秒
            long duration = grabber.getLengthInTime();
            long startTime = (long) (start * 1000 * 1000);
            long endTime = (long) (end * 1000 * 1000);
            if(startTime >= duration || endTime >= duration){
                log.error("file:{} 时长过短,duration:{}",inputFilePath,duration);
                return null;
            }

            int imageWidth = grabber.getImageWidth();
            int imageHeight = grabber.getImageHeight();
            int audioChannels = grabber.getAudioChannels();

            recorder = new FFmpegFrameRecorder(outputFile, imageWidth,
                    imageHeight, audioChannels);
            recorder.setVideoCodec(grabber.getVideoCodec());
            recorder.setVideoBitrate(grabber.getVideoBitrate());
            recorder.setAudioBitrate(grabber.getAudioBitrate());
            recorder.setFrameRate(grabber.getFrameRate());
            recorder.setFormat(FitterFormat);
            recorder.start();

            Frame f = null;
            while (true){
                f = grabber.grabFrame();
                if (null == f) break;
                if(f.timestamp > endTime) {
                    break;
                }
                if (f.timestamp >= startTime) {
                    recorder.record(f);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }
                if (recorder != null) {
                    recorder.stop();
                    recorder.release();
                }
            } catch (FFmpegFrameGrabber.Exception | FFmpegFrameRecorder.Exception e) {
                log.error("cutVideoSecond grabber.release failed");
            }
        }
        return outputFile;
    }
    
    /**
     * 视频文件合并
     *
     * @param fileList   视频文件列表
     * @param outputFile 输出文件
     **/
    public static String splicing(List<String> fileList) {
        if (null == fileList || fileList.size() <= 0) {
            log.error("fileList is null");
            return null;
        }
        StringBuffer output = new StringBuffer();
		output.append("./media/").append(DateUtils.dateToStr(new Date(), yyyyMMdd)).append("/splicing").append("/");
		String outputPath = output.toString();
		
		String outputFile = outputPath +System.currentTimeMillis()+ Suffix + FitterFormat;
		
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;

        FileUtil.judeDirExists(new File(outputPath));
        try {
            for (int i = 0; i < fileList.size(); i++) {
                grabber = new FFmpegFrameGrabber(fileList.get(i));
                grabber.setOption(TimeoutOption.RW_TIMEOUT.getKey(), timeout);
                grabber.start();
                if (i == 0) {
                    recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(),
                            grabber.getImageHeight(), grabber.getAudioChannels());
                    recorder.setVideoCodec(grabber.getVideoCodec());
                    recorder.setVideoBitrate(grabber.getVideoBitrate());
                    recorder.setAudioBitrate(grabber.getAudioBitrate());
                    recorder.setFrameRate(grabber.getFrameRate());
                    recorder.setFormat(FitterFormat);
                    recorder.start();
                }
                Frame f = null;
                while (true) {
                    f = grabber.grabFrame();
                    if (f == null) {
                        if (grabber != null) {
                            grabber.stop();
                            grabber.release();
                        }
                        break;
                    }
                    recorder.record(f);
                }
            }


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }
                if (recorder != null) {
                    recorder.stop();
                    recorder.release();
                }
            } catch (FFmpegFrameGrabber.Exception | FFmpegFrameRecorder.Exception e) {
                log.error("merge release failed");
            }
        }
        return outputFile;
    }
    
    
    /**

     * **/
    public static List<ImageInfo> capture(String inputFilePath,int time, int sum,String imageFormat){
        FFmpegFrameGrabber grabber = null;
        FFmpegFrameRecorder recorder = null;

		StringBuffer output = new StringBuffer();
		output.append("./image/").append(DateUtils.dateToStr(new Date(), yyyyMMdd)).append("/capture").append("/");
		String outputPath = output.toString();
        FileUtil.judeDirExists(new File(outputPath));
        
        List<ImageInfo> imageList = Lists.newArrayList();

        try {
            grabber = new FFmpegFrameGrabber(inputFilePath);
            grabber.setOption(TimeoutOption.RW_TIMEOUT.getKey(), timeout);
            grabber.start();
            if (grabber.getLengthInVideoFrames() == 0 || grabber.getVideoFrameRate() == 0) {
                log.error("file:{} 信息不全",inputFilePath);
                return null;
            }
            int lenght = grabber.getLengthInFrames();
            int imageWidth = grabber.getImageWidth();
            int imageHeight = grabber.getImageHeight();
            String rotate = grabber.getVideoMetadata("rotate");// 视频的旋转角度
    		// 时长 单位 s
    		int duration = (int) (lenght / grabber.getVideoFrameRate());
    		int i = 0;
    		int j = 0;
    		Frame f = null;
    		
    		long nexttime = 0,timestamp=0;
    		
    		int scInt = (int) (time * 1000 * 1000);

    		while (true) {
    			f = grabber.grabFrame();
    			if (null == f) {
    				break;
    			}
    			if (f.timestamp >= nexttime) {
    				timestamp = f.timestamp;
    				// 若显示帧不为关键帧，则寻找相邻的下一帧
    				if (f.image != null) {
    					IplImage src = null;
    					if (null != rotate && rotate.length() > 1) {
    						OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
    						src = converter.convert(f);
    						f = converter.convert(rotate(src, Integer.valueOf(rotate)));
    					}
    					String imageName = System.currentTimeMillis()+ Suffix + imageFormat;
    					String outputFile = outputPath +imageName;
    					doExecuteFrame(f,outputFile);
    					ImageInfo info = new ImageInfo();
    					info.setPath(outputFile);
    					info.setName(imageName);
    					info.setWidth(imageWidth);
    					info.setHeight(imageHeight);
    					imageList.add(info);
    					
    					nexttime += scInt;
    					j++;
    					if (j == 1) {
    						nexttime += timestamp;
    					}
    					log.info("video-当前图片张数：{}，视频第{}帧，当前视频时间：{}，下次切图时间：{}，", j, i, timestamp, nexttime);
    				}
    			}
    			i++;
    			if (nexttime >= (duration * 1000 * 1000)) {
    				break;
    			}
    			if (j >= sum) {
    				break;
    			}
    		}


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (grabber != null) {
                    grabber.stop();
                    grabber.release();
                }
            } catch (FFmpegFrameGrabber.Exception e) {
                log.error("cutVideoSecond grabber.release failed");
            }
        }
        return imageList;
    }
    
	public static IplImage rotate(IplImage src, int angle) {
		IplImage img = IplImage.create(src.height(), src.width(), src.depth(), src.nChannels());
		opencv_core.cvTranspose(src, img);
		opencv_core.cvFlip(img, img, angle);
		return img;
	}
	
	/**
	 * 输出成本地图片
	 */
	public static void doExecuteFrame(Frame f, String targetFileName) {
		if (null == f || null == f.image) {
			return;
		}
		Java2DFrameConverter converter = new Java2DFrameConverter();
		BufferedImage bi = converter.getBufferedImage(f);
		File output = new File(targetFileName);
		try {
			ImageIO.write(bi, "jpg", output);

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
